// 手写MyPromise

// 手写MyPromise-核心
/*
Step1: Promise是一个类 其构造器接收一个执行器函数 promise对象内部状态 resolve/reject方法 then方法
Step2: then方法调用时可能还未得到promise对象的终态
Step3: promise的then方法可以添加多个(多次调用)
Step4: promise的then方法可以链式调用
Step5: then的链式调用 处理前一个then调用若返回promise 而该promise尚未得到终态的情况
Step6: 禁止then方法的回调返回自身、
       内部的错误捕获、
       将then方法的参数变为可选参数（如果一个then方法无回调函数传入，则其后面有回调函数的then方法来处理拿到的成功的值或失败的原因）、
       Promise.all静态方法、
       Promise.resolve静态方法、
       promise对象的finally方法、
       promise对象的catch方法
*/
 
// promise对象的状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
 
class MyPromise {
    constructor(executor){                   // new MyPromise() 接收一个执行器函数
        try{ // 内部的错误捕获
            executor(this.resolve, this.reject)  // 执行器函数有两个参数：resolve和reject 是内部方法
        } catch(e) {
            this.reject(e)
        }
        
    }
 
    status = PENDING                         // 标识该promise对象的状态
    value = undefined                        // resolve方法接收的参数：如果对象成功了，那么传入的数据是什么
    reason = undefined                       // reject方法接收的参数：如果对象失败了，那么失败的原因是什么
    successCallback = []
    failCallback = []
 
    resolve = value => {                     // 用于把promise对象的状态更改为fulfilled-成功
        if(this.status !== PENDING) return;  // promise对象状态只能由pending-等待 变成 成功或失败
        this.status = FULFILLED
        this.value = value                   // 成功了的数据保存在this.value中 后续传递给成功的回调函数
        
        while(this.successCallback.length){  // 如果有保存而未执行的成功回调 则此时执行
            const callback = this.successCallback.shift() // 回调函数数组的第一个先执行
            callback()
        }
    }
    reject = reason => {                     // 用于把promise对象的状态更改为rejected-失败
        if(this.status !== PENDING) return;
        this.status = REJECTED
        this.reason = reason                 // 失败了的原因保存在this.reason中 后续传递给失败的回调函数
        // 如果有保存而未执行的失败回调 则此时执行
        while(this.failCallback.length){
            const callback = this.failCallback.shift()
            callback()
        }
    }
 
    then = (successCallback, failCallback) => { // promise对象得到终态后的回调是什么
        successCallback = successCallback ? successCallback : value => value     // 将then方法的参数变为可选参数
        failCallback = failCallback ? failCallback : reason => { throw reason }  // 将then方法的参数变为可选参数
 
        let promise2 = new MyPromise((resolve, reject) => { // 执行器内的代码立即执行
 
            if(this.status == FULFILLED){
                setTimeout(() => {
                    try {  // 内部的错误捕获
                        let x = successCallback(this.value)    // 上一个promise对象回调函数的返回值 需要传递给下一个promise对象的回调函数
                        // 这里需要判断上一个promise对象回调函数的返回值x是普通值 还是另一个promise对象
                        // 如果是普通值，则直接返回x
                        // 如果是promise对象，则应等待该promise对象执行完毕（得到终态）
                        //   该promise对象执行完毕的结果 如果是成功，则把成功的值传递给下一个then方法的成功回调
                        //   如果是失败，则把失败的原因传递给一下一个then方法的失败回调
                        handlePromiseReturned(promise2, x, resolve, reject)
                    } catch(e) {
                        reject(e)
                    }
                }, 0)
            } else if(this.status == REJECTED){
                setTimeout(() => {
                    try{ // 内部的错误捕获
                        let x = failCallback(this.reason)
                        handlePromiseReturned(x, resolve, reject)
                    } catch(e){
                        reject(e)
                    }
                }, 0)
            } else {                             // 调用then方法时，promise还没有得到终态
                                                 // 要等到其得到终态后，再执行成功或失败的回调
                                                 // 先把回调都存储起来
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try{ // 内部的错误捕获
                            let x = successCallback(this.value)
                            handlePromiseReturned(promise2, x, resolve, reject)
                        } catch(e) {
                            reject(e)
                        }
                    }, 0)
                })
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try{ // 内部的错误捕获
                            let x = failCallback(this.reason)
                            handlePromiseReturned(promise2, x, resolve, reject)
                        } catch(e){
                            reject(e)
                        }
                    }, 0)
                })
            }
 
        })
        return promise2
    }
 
    finally = (callback) => { // finally接收一个回调函数 在promise得到终态后执行
                              // finally后面仍可以链式调用then() 后面的then()会等待finally回调函数执行完毕（得到终态）
        this.then(value => {
            // callback()
            return MyPromise.resolve(callback()) // MyPromise.resolve把一个值转换成promise
                    .then(() => value)           // 把promise成功的值返回
        }, reason => {
            return MyPromise.resolve(callback()).then(() => { throw reason })
        })
    }
    
    catch = failCallback => {
        return this.then(undefined, failCallback)
    }
 
    static all = (array) => { // Promise.all方法的返回值是一个promise对象
        return new MyPromise((resolve, reject) => {
            let results = []
            let count = 0
            function addResult(key, result){
                results[key] = result
                count++
                if(count == array.length){
                    resolve(results)
                }
            }
            for(let i = 0; i < array.length; i++){
                const current = array[i]
                if(current instanceof MyPromise){
                    current.then(value => {
                        addResult(i, value)
                    }, reason => {
                        reject(reason) // array中的任何一个promise失败，则Promise.all返回的promise就是状态失败
                    })
                } else {
                    addResult(i, current)
                }
            }
        })
    }
 
    static resolve = value => { // Promise.resolve方法把传入的值包装成promise对象 如果参数就是promise对象，则直接返回
        if(value instanceof MyPromise) return value
        return new MyPromise((resolve, reject) => {
            resolve(value)
        })
    }
}
 
function handlePromiseReturned(promise2, x, resolve, reject){
    if(x instanceof MyPromise){
 
        if(promise2 === x) return reject(new Error('禁止then方法的回调返回自身')); // 禁止then方法的回调返回自身
 
        x.then(value => {
            resolve(value) // then方法将要返回的promise对象的 resolve方法
        }, reason => {
            reject(reason) // then方法将要返回的promise对象的 reject方法
        })
    } else {
        resolve(x)
    }
}
 
/* 测试 */
function users(){
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(['Andy', 'Heiby'])
        }, 1000)
    })
}
 
var promise = new MyPromise((resolve, reject) => {
    resolve('成功的值')
})
 
// then()方法参数可选
 
const r1 = promise.then(console.log, console.log)
const r2 = promise.then().then().then(console.log, console.log)

/*
输出结果（立即输出）：
成功的值
成功的值
 */
 
 
// Promise.all静态方法
/* 
function p1(){
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve('p1')
        }, 2000)
    })
}
function p2(){
    return new MyPromise((resolve, reject) => {
        resolve('p2')
    })
}
var promiseAll = MyPromise.all(['a', 'b', p1(), p2(), 'c'])
    .then(values => {
        console.log(values)
    }, reason => {
        console.log('error: ', reason)
    })
*/
/*
输出结果（2秒后输出）：
[ 'a', 'b', 'p1', 'p2', 'c' ]
 */
 